/******************************************************************************
 * Copyright (C) 2025 COMPANY or its affiliates.
 * 
 * All Rights Reserved.
 * 
 @file bsp_flash.c
 * 
 @par dependencies 
 - bsp_flash.h  // 对应头文件
 * 
 @author liubin | R&D Dept. | COMPANY
 * 
 @brief 模块核心功能实现，包括：
            - 功能点1：xxx初始化与配置
            - 功能点2：xxx数据处理与交互
            - 功能点3：xxx资源管理与释放
 * 
 Processing flow:
 * 1. 初始化阶段：
            - 调用xxx_init()完成硬件/软件初始化
            - 初始化全局变量与静态变量
            - 注册回调函数（如需要）
 * 2. 运行阶段：
            - 接收输入数据（如xxx_rx()）
            - 调用核心处理函数（如xxx_process()）
            - 输出处理结果（如xxx_tx()）
 * 3. 销毁阶段：
            - 调用xxx_deinit()释放资源
            - 重置变量状态（如需要）
 * 
 @version V1.0 2025-11-09
 *
 @note 1 tab == 4 spaces!
 *       - 实现说明：如使用DMA传输、中断优先级配置
 *       - 性能限制：如最大处理速率、内存占用上限
 *       - 调试提示：关键日志输出位置、断点设置建议
 *
 *****************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "bsp_flash.h"

#include "stm32f4xx_hal_flash.h"
/* Private typedef -----------------------------------------------------------*/

#define USE_ELOG 0
#if USE_ELOG
#include "elog.h"
#define TAG "bsp_flash"
#define TRACE(fmt, ...) elog_i(TAG, fmt, ##__VA_ARGS__)

#else
#define TAG "bsp_flash"
#define TRACE(fmt, ...) 


#endif // USE_ELOG

/* Private define ------------------------------------------------------------*/


const uint32_t Flash_Sectorsize[8] = 
{ 
    FLASH_SECTOR_0, //Sector 0 (16KB)
    FLASH_SECTOR_1, //Sector 1 (16KB)
    FLASH_SECTOR_2, //Sector 2 (16KB)
    FLASH_SECTOR_3, //Sector 3 (16KB)
    FLASH_SECTOR_4, //Sector 4 (64KB)
    FLASH_SECTOR_5, //Sector 5 (128KB)
    FLASH_SECTOR_6, //Sector 6 (128KB)
    FLASH_SECTOR_7  //Sector 7 (128KB)
};

// 扇区地址边界数组
const uint32_t sectorAddrs[] = {
    ADDR_FLASH_SECTOR_0,  // 0x08000000
    ADDR_FLASH_SECTOR_1,  // 0x08004000
    ADDR_FLASH_SECTOR_2,  // 0x08008000
    ADDR_FLASH_SECTOR_3,  // 0x0800C000
    ADDR_FLASH_SECTOR_4,  // 0x08010000
    ADDR_FLASH_SECTOR_5,  // 0x08020000
    ADDR_FLASH_SECTOR_6,  // 0x08040000
    ADDR_FLASH_SECTOR_7   // 0x08060000
};
/* Private macro -------------------------------------------------------------*/


/* Private variables ---------------------------------------------------------*/


/* Global variables ----------------------------------------------------------*/


/* Private function prototypes -----------------------------------------------*/


/* Global function prototypes -------------------------------------------------*/


/* Private functions ---------------------------------------------------------*/


/* Global functions ----------------------------------------------------------*/

/**
  * @brief  根据指定的地址获取对应的Flash扇区编号
  * @param  addr: Flash地址
  * @retval 返回对应地址所在的Flash扇区编号，如果地址超出所有扇区范围则返回FLASH_SECTOR_0
  */
static uint16_t STMFLASH_GetFlashSector(uint32_t addr)
{
    //elog_i(TAG,"addr :%x",addr);
    // 查找地址所属的扇区
    for (int i = 0; i < sizeof(sectorAddrs) / sizeof(sectorAddrs[0]); i++) {
        if (addr < sectorAddrs[i]) {
            return Flash_Sectorsize[i];
        }
    }
    //elog_w(TAG,"addr out of range");
    // 如果地址超出所有定义的扇区范围，返回第一个扇区
    return FLASH_SECTOR_0;
}

/* Private functions ---------------------------------------------------------*/
static uint16_t bsp_flash_get_sector(uint32_t addr)
{
    return STMFLASH_GetFlashSector(addr);
}

/* extern variables ----------------------------------------------------------*/

void bsp_flash_unlock(void)
{
    HAL_FLASH_Unlock();
}

void bsp_flash_lock(void)
{
    HAL_FLASH_Lock();
}

uint8_t bsp_flash_erase_sector(uint32_t sector_addr)
{
    FLASH_EraseInitTypeDef EraseInitStruct;
    uint32_t SectorError = 0;
    uint8_t ret = 0;
    
    bsp_flash_unlock();
    
    /* 填充擦除结构体 */
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
    EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
    EraseInitStruct.Sector = sector_addr;
    EraseInitStruct.NbSectors = 1;
    
    /* 执行擦除操作 */
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK)
    {
        ret = 1; // 擦除失败
    }
    
    bsp_flash_lock();
    return ret;
}

int bsp_flash_write(uint32_t addr, uint32_t data)
{
    int ret;
    
    bsp_flash_unlock();
    
    /* 写入一个32位数据 */
    ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, data);
    
    if(ret == HAL_OK)
    {
        TRACE("write success");
    }
    else
    {
        TRACE("write fail");
    }
    
    bsp_flash_lock();
    return ret;
}


/**
  * @brief  向Flash中写入多个32位数据
  * @param  addr: 写入的起始地址
  * @param  data: 指向要写入数据的指针
  * @param  size: 要写入的数据个数(32位为单位)
  * @retval int: 写入结果状态
  *          HAL_OK: 写入成功
  *          其他值: 写入失败
  */
int bsp_flash_write_words(uint32_t addr, uint32_t *data, uint16_t size)
{
    int ret = HAL_OK;
    
    /* 解锁Flash以允许写入操作 */
    bsp_flash_unlock();
    
    /* 循环写入多个32位数据到Flash */
    for(int i = 0; i < size; i++)
    {
        ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + (i * 4), *(data + i));
        if(ret != HAL_OK)
        {
            break; // 写入失败，退出循环
        }
    }

    if(ret == HAL_OK)
    {
        TRACE("write success");
    }
    else
    {
        TRACE("write fail");
    }

    /* 完成写入操作后锁定Flash */
    bsp_flash_lock();
    return ret;
}

/**
  * @brief  This function is used to erase the flash area.
  * @param  addr: 起始地址
  * @param  size: 要擦除的大小
  * @retval 0 : Success
  *         1 : Fail
  */
uint8_t bsp_flash_erase(uint32_t addr, uint32_t size)
{
    FLASH_EraseInitTypeDef EraseInitStruct;
    uint32_t SectorError = 0;
    uint32_t flash_start_sector = 0;
    uint32_t flash_end_sector = 0;
    
    // 获取起始和结束扇区
    flash_start_sector = bsp_flash_get_sector(addr);
    flash_end_sector = bsp_flash_get_sector(addr + size);
    
    bsp_flash_unlock();
    
    /* 填充擦除结构体 */
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
    EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
    EraseInitStruct.Sector = flash_start_sector;
    EraseInitStruct.NbSectors = flash_end_sector - flash_start_sector + 1;
    
    /* 执行擦除操作 */
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK)
    {
        bsp_flash_lock();
        return 1; // 擦除失败
    }
    
    bsp_flash_lock();
    return 0; // 擦除成功
}